Skip to content

feat(reporting): negotiated contracts for automatic breakdowns - #6627

Merged
bokelley merged 14 commits into
mainfrom
reporting-auto-breakdowns
Aug 23, 2026
Merged

feat(reporting): negotiated contracts for automatic breakdowns#6627
bokelley merged 14 commits into
mainfrom
reporting-auto-breakdowns

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Summary

Top of the stack (#6618#6622#6626 → this; bases retarget as the stack merges). Implements RFC #6623.

by_creative, by_keyword, and by_catalog_item were returned automatically with no limit, sort_by, or truncation disclosure — so "top creatives by quartile_100" (sortable as of #6618) had no completeness contract, and a seller returning 50 of 500 creative rows couldn't say which 50 or whether the list was complete.

The dual contract

  • Key omitted (today's behavior, unchanged): sellers return rows at their discretion; no truncation contract; the new response fields are RECOMMENDED, not required. Every existing conformant emission stays conformant.
  • Key present (even as {}): limit/sort_by/sort_direction are honored, and by_X_truncated + the applied-sort echo (by_X_sorted_by/by_X_sort_direction) become MUST.

The per-review scoping matters: the echo/truncation MUSTs bind to request-key presence, not array presence — an unconditional MUST would have retroactively broken every existing automatic emission. Since reporting_dimensions is additionalProperties: true, pre-3.2 sellers silently ignore the new keys; the applied-sort echo is therefore the capability-detection signal (its absence on a keyed request means the seller doesn't implement negotiation).

The three dimensions carry the full deterministic sort semantics from #6622 (row-grain fallback, nulls-last ordering, direction MUST), and the schema-derived invariant test in the sort-contract suite automatically covers them — a sortable dimension can no longer ship without the echo contract.

Relationship: #5671 (breakdown continuation) remains the complement — sort+limit gets the top-N, continuation gets the rest; both share truncation semantics.

🤖 Generated with Claude Code

bokelley and others added 8 commits August 17, 2026 00:59
quartile_25..quartile_100 and the viewability leaves (viewable_rate,
viewable_impressions, measurable_impressions, viewed_seconds) become
first-class metric identities in available-metric and sort-metric,
resolving to their nested canonical values with no duplicate flat
fields. Closes the existing contradiction where committed-metric
qualifier rules and the delivery-metric-aggregate viewable_rate
conditional referenced unrepresentable metric_ids and shipped examples
failed their own schemas. Also restores sort-metric's claimed coverage
of flat numeric delivery metrics (cpm, cost_per_completed_view,
downloads, units_sold, new_to_brand_units, plays, commissionable_value),
with lift scalars documented as intentionally sort-excluded. Adds a
metric-identity coherence contract test enforcing enum/schema/example
agreement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Breakdown sorting was descending-only with a silent fallback to spend
when the seller does not report the requested metric — an agentic buyer
asking for top geos by completion_rate gets spend-ordered rows and
reasons over them as completion-ordered. Add sort_direction (asc/desc,
default desc) to the six sortable dimensions, enabling bottom-N queries
that cannot be recovered from a truncated descending pull, and a
per-breakdown applied-sort echo (by_X_sorted_by / by_X_sort_direction,
MUST whenever the breakdown is present) so the fallback is visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reporting webhook can narrow which metrics are delivered
(reporting_webhook.requested_metrics); the GET path could not, so the
interactive surface where agent context budget matters most always paid
full payload cost. Add the same narrowing to the request: omitted means
unchanged full payloads; impressions and spend are always included;
requesting a leaf metric identity returns its canonical nested carrier;
and missing_metrics MUST NOT flag absences caused solely by request
narrowing. Implements RFC #6624.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Leaf identities split the metric vocabulary into container and leaf
tokens, which made token-equality set operations ambiguous: a product
declaring viewability could be silently excluded by a required_metrics
filter for viewable_rate, and a format/product intersection of mixed
declarations could yield the empty set. State the rule once in
available-metric (container subsumes its leaves; leaf selects its
carrier; a leaf implies neither siblings nor the carrier's other
fields) and cite it from required_metrics, reported_metrics, and
requested_metrics. Also: sellers MUST populate viewability.standard
when the commitment carries a viewability_standard qualifier, and the
leaf-identity docs paragraph no longer splits the metric bullet list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review findings: the six sort_by descriptions still claimed descending-
only next to the new sort_direction field; the spend fallback had no
grain (package vs row) so two conformant sellers could return disjoint
top-N sets; rows lacking the sort metric had undefined order (NULLS
FIRST vs LAST) exactly where bottom-N queries live; and direction had
no honor rule, letting a fallback gut the asc use case. Canonical rule
now at every site: fallback triggers only when the metric is not
reported at the breakdown's row grain, direction resets to desc on
metric fallback and is otherwise a MUST, rows lacking the applied
metric order last. Sortable-dimension invariants are now derived from
the schema instead of a hardcoded list, so a future sortable dimension
cannot ship without the echo contract. Also fixes the stale descending
claim in managing-response-size.mdx.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	docs/media-buy/media-buys/optimization-reporting.mdx
by_creative, by_keyword, and by_catalog_item were returned automatically
with no limit, sort, or truncation disclosure, so "top creatives by
quartile_100" had no completeness contract. Including their keys in
reporting_dimensions now upgrades them to the negotiated contract:
limit/sort_by/sort_direction honored, by_X_truncated and the
applied-sort echo become binding. Omitting the keys preserves the
automatic behavior exactly — the MUSTs are scoped to request-key
presence, so existing automatic emissions stay conformant. The new
dimensions carry the full deterministic sort semantics (row-grain
fallback, nulls-last, direction MUST). Implements RFC #6623.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema paths require human/CODEOWNERS approval.

This PR modifies two published protocol schema files under static/schemas/source/**:

  • get-media-buy-delivery-request.json
  • get-media-buy-delivery-response.json

gated_paths is true and review_decision is not APPROVED (unknown/none), so the hard approval gate (decision rule row 2) fires: the outcome must be escalate, not approve.

The change itself looks clean per the reviewer: an additive, backward-compatible minor (RFC #6623) making automatic creative/keyword/catalog_item breakdowns optionally negotiable via reporting_dimensions, with a dual MUST/RECOMMENDED contract keyed to request-key presence. Schema↔docs coherence holds, reporting_dimensions is additionalProperties:true, echo/truncation MUSTs bind to request-key presence, and a correct minor changeset is present. No blocking or Medium findings were raised.

Nonetheless, the gated schema paths require an explicit human/CODEOWNERS approval before merge. Once review_decision becomes APPROVED, this PR can fall through to a normal approve on its clean diff.

Why human review

  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-request.json — human/CODEOWNERS review required (review_decision is not APPROVED)
  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-response.json — human/CODEOWNERS review required (review_decision is not APPROVED)
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/media-buy/get-media-buy-delivery-request.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-media-buy-delivery-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

bokelley and others added 2 commits August 17, 2026 11:32
Ladon review: "same semantics as reporting_webhook.requested_metrics"
was not literally true — the GET field adds minItems: 1 and the
always-included impressions/spend rule was stated only on the GET side.
State the impressions/spend rule on the webhook field too, define the
webhook's empty-array case as equivalent to omission, and describe the
one intentional shape difference explicitly on both sides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema files touched without a recorded APPROVED review.

This PR modifies two files under the hard, non-overridable approval gate static/schemas/source/**:

  • static/schemas/source/media-buy/get-media-buy-delivery-request.json
  • static/schemas/source/media-buy/get-media-buy-delivery-response.json

gated_paths is true and review_decision is not APPROVED (unknown/none). Per decision-table row 2, the outcome must be escalate until a human/CODEOWNERS approval is recorded. This is a mechanical, path-based gate — a clean diff cannot lift it.

Findings: none. The reviewer confirms the delta since the prior clean pass is description-only refinements to requested_metrics cross-referencing reporting-webhook.json and the delivery-request field. Descriptions match their schemas and each other; no wire-shape, required[], or enum changes; nothing blocking or Medium.

Escalation reasons: hard gated-path approval requirement, pending human review. Once review_decision becomes APPROVED, this clean diff falls through to approve.

Why human review

  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-request.json — human/CODEOWNERS review required (review_decision is not APPROVED)
  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-response.json — human/CODEOWNERS review required (review_decision is not APPROVED)
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/media-buy/get-media-buy-delivery-request.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-media-buy-delivery-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

bokelley and others added 3 commits August 17, 2026 11:54
…face

The empty-array-equals-omission rule was stated only on the GET
request's description; a reader of reporting-webhook.json alone could
derive empty = impressions+spend only. State it where it applies.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verification review: two task-reference sentences stated unconditional
MUSTs ("whenever the corresponding breakdown array is present") that
the schema correctly scopes to request-key presence — the unconditional
form would retroactively bind automatic creative/keyword/catalog_item
emissions. Docs now match the schema contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladon verdict: Escalate to human review

Escalate — gated schema paths modified without an APPROVED review decision.

This PR modifies two files under static/schemas/source/**, which sit behind a hard, deterministic approval gate (gated_paths: true). The current review_decision is unknown/none, not APPROVED, so the gate is not satisfied and Ladon cannot auto-approve regardless of how clean the diff is (decision rule row 2).

The reviewer found no critical/high/medium issues: the delta since the prior clean pass is two prose/description clarifications. get_media_buy_delivery.mdx scopes the echo/truncation MUST to requested dimensions and marks automatic creative/keyword/catalog_item fields RECOMMENDED, coherent with the response schema verbatim. The webhook requested_metrics empty==omitted definition agrees with the get_media_buy_delivery cross-reference. No schema drift, no wire-shape change, changeset present. This mirrors the prior escalate, which persists here on the gate alone (not sticky row 6 — there are no fresh findings, but row 2 fires independently and deterministically).

Escalation reasons

  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-request.json — human/CODEOWNERS review required (review_decision not APPROVED).
  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-response.json — human/CODEOWNERS review required (review_decision not APPROVED).

Once a human/CODEOWNERS approval is recorded, this PR can fall through to a normal approve on its clean diff.

Why human review

  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-request.json under static/schemas/source/** — human/CODEOWNERS review required because review_decision is not APPROVED
  • Modifies gated schema file static/schemas/source/media-buy/get-media-buy-delivery-response.json under static/schemas/source/** — human/CODEOWNERS review required because review_decision is not APPROVED
  • This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/media-buy/get-media-buy-delivery-request.json (modified) matches static/schemas/source/**; static/schemas/source/media-buy/get-media-buy-delivery-response.json (modified) matches static/schemas/source/**) and the current GitHub review decision is 'unknown', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.

Base automatically changed from reporting-requested-metrics to main August 23, 2026 15:31
…owns

# Conflicts:
#	.changeset/metric-leaf-identities.md
#	docs/media-buy/media-buys/optimization-reporting.mdx
#	docs/media-buy/task-reference/get_media_buy_delivery.mdx
#	package.json
#	static/schemas/source/enums/available-metric.json
#	static/schemas/source/enums/sort-metric.json
@bokelley
bokelley merged commit 6b4525e into main Aug 23, 2026
58 checks passed
@bokelley
bokelley deleted the reporting-auto-breakdowns branch August 23, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ladon/needs-human-review Ladon has escalated this PR for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant